package org.zetaframework.satoken.interceptor;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.web.servlet.HandlerInterceptor;
import org.zetaframework.core.utils.ContextUtil;

import java.util.Arrays;

/**
 * 清空ThreadLocal数据拦截器
 * <p>
 * 说明：<br>
 * 执行完Controller之后清空ContextUtil中ThreadLocal的值
 *
 * @author gcc
 */
public class ClearThreadLocalInterceptor implements HandlerInterceptor {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    /**
     * 拦截路径
     * <p>
     * 说明：
     * <pre>
     * 为什么在这里拦截而不是在网关拦截？
     * 因为直接访问某个微服务的druid和swagger-ui时不会走网关，所以在这里进行拦截并处理
     * </pre>
     */
    public static final String[] INTERCEPT_PATH = {
            // 拦截访问druid时的/favicon.ico请求
            "/favicon.ico",
            // 拦截chrome浏览器的访问请求
            "/.well-known/appspecific/com.chrome.devtools.json",
    };

    /**
     * 每次请求之前触发的方法
     *
     * @param request HttpServletRequest
     * @param response HttpServletResponse
     * @param handler Object
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String path = request.getServletPath();
        logger.debug("本次请求的请求路径为: {}", path);
        if (Arrays.asList(INTERCEPT_PATH).contains(path)) {
            response.setStatus(HttpStatus.NOT_FOUND.value());
            return false;
        }
        return HandlerInterceptor.super.preHandle(request, response, handler);
    }

    /**
     * 执行完Controller之后，要做的事
     *
     * @param request HttpServletRequest
     * @param response HttpServletResponse
     * @param handler Object
     * @param ex Exception
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // 清空ThreadLocal的值，防止下次请求时获取到的值是旧数据，同时也能防止内存溢出
        ContextUtil.remove();
    }
}
